package chen.yi.component.code.generator.utils;

import chen.yi.component.common.exception.BizException;
import freemarker.cache.ClassTemplateLoader;
import freemarker.cache.FileTemplateLoader;
import freemarker.cache.MultiTemplateLoader;
import freemarker.cache.TemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.util.concurrent.ConcurrentHashMap;

import static chen.yi.component.code.generator.enums.CodeErrorEnums.LOADING_TEMPLATE;

/**
 * 模板读取工具类
 * @author huat
 **/
@org.springframework.context.annotation.Configuration
@Slf4j
public class TemplateUtils {
    private  final Configuration cfg = new Configuration(Configuration.VERSION_2_3_32);
    private  final ConcurrentHashMap<String, Template> TEMPLATE_CACHE = new ConcurrentHashMap<>();
    private final static String EXTERNAL_PATH=System.getProperty("user.dir").replaceAll("\\\\","/")+"/templates/code";

    protected TemplateUtils() {
    }
    @PostConstruct
    public void initTemplate() throws IOException {
        ClassTemplateLoader classLoader = new ClassTemplateLoader(this.getClass(), "/templates/code");
        File file = new File(EXTERNAL_PATH);
        MultiTemplateLoader multiLoader =null;
       if(file.exists()){
           FileTemplateLoader fileLoader = new FileTemplateLoader(file);
           // 使用MultiTemplateLoader组合加载器
           multiLoader=new MultiTemplateLoader(new TemplateLoader[]{fileLoader,classLoader });
       }else{
           multiLoader=new MultiTemplateLoader(new TemplateLoader[]{classLoader });
       }

        cfg.setTemplateLoader(multiLoader);

        cfg.setDefaultEncoding("UTF-8");
        cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
        loadAllTemplates();

    }
    /**
     * 模板数据
     *
     * @param templateName 模板名称
     * @param data         需要填充的数据
     * @return 填充后的数据字符串
     */
    protected String templateData(String templateName, Object data) {
        Template template = TEMPLATE_CACHE.get(templateName);
        StringWriter writer = new StringWriter();
        try {
            template.process(data, writer);
        } catch (TemplateException | IOException e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException(e);
        }
        return writer.toString();
    }

    /**
     * 重新加载模板
     */
    public  void againGetTemplate() {
        try {
            TEMPLATE_CACHE.clear();
            cfg.clearTemplateCache();
            loadAllTemplates();
            log.info(" 重新加载模板成功");
        } catch (IOException e) {
            log.error(" 重新加载模板失败");
            throw new BizException(LOADING_TEMPLATE.getCode(), LOADING_TEMPLATE.getMessage());
        }
    }


    /**
     * 加载模板到缓存
     */
    private  void loadAllTemplates() throws IOException {
        //预加载项目同级ddlTemplates目录下模板，如果模板名称一样则使用外部模板
        Resource[] externalResources = new PathMatchingResourcePatternResolver()
                .getResources("file:" + EXTERNAL_PATH + "/**/*.ftl");
        for (Resource resource : externalResources) {
            String name = resource.getFilename();
            TEMPLATE_CACHE.put(name, cfg.getTemplate(name));
        }
        // 预加载所有resource下模板
        Resource[] resources = new PathMatchingResourcePatternResolver()
                .getResources("classpath:/templates/code/**/*.ftl");
        for (Resource resource : resources) {
            String name = resource.getFilename();
            TEMPLATE_CACHE.put(name, cfg.getTemplate(name));
        }
    }
}
